#include "SLLE.h"
#include "Poco/UUIDGenerator.h"
#include "../../Log/NetLog.h"
#include "SPHY.h"

using namespace std;

SLLE* SLLE::m_pInstance = NULL;

SLLE* SLLE::Initialize()
{
    return GetInstance();
}

SLLE* SLLE::GetInstance()
{
    if (m_pInstance == NULL)
    {
        static Poco::Mutex s_mutex;
        Poco::Mutex::ScopedLock lock(s_mutex);
        if (m_pInstance == NULL)
        {
            m_pInstance = new SLLE;
        }
    }
    return m_pInstance;
}

int SLLE::Start()
{
    try
    {
        if (m_bStop == true)
        {
            //m_ready.set();
            m_thread.start(*this);
            m_bStop = false;
            //m_ready.wait();
        }
    }
    catch (...)
    {
        g_NetLog.Error("catched\n");
        return -1;
    }
}

int SLLE::Stop()
{
    try
    {
        if (m_bStop == false)
        {
            m_bStop = true;
            m_thread.join();
        }
        return 0;
    }
    catch (...)
    {
        g_NetLog.Error("catched\n");
        return -1;
    }
}

void SLLE::write(std::string strSCSFUUID, std::string strMethod, std::string strData)
{
    Poco::UUIDGenerator &gen = Poco::UUIDGenerator::defaultGenerator();
    std::string strUUID = gen.createRandom().toString();
    std::string strSLLE = strSCSFUUID + std::string(",") + strMethod + std::string(",") + strData;
    if (strSLLE.size() > MAX_SLLE_LENGTH)
    {
        std::string strTotal;
        if (strSLLE.size() % MAX_SLLE_LENGTH == 0)
        {
            strTotal = Int2String(strSLLE.size() / MAX_SLLE_LENGTH);
        }
        else
        {
            strTotal = Int2String(strSLLE.size() / MAX_SLLE_LENGTH + 1);
        }
        std::string strEle;
        int iIndex = 0;
        do
        {
            std::string strIndex = Int2String(iIndex);
            iIndex += 1;
            if (strSLLE.size() < MAX_SLLE_LENGTH)
            {
                strEle = strUUID + std::string(",") + strTotal + std::string(",") + strIndex + std::string(",") + strSLLE;
                strSLLE.clear();
            }
            else
            {
                strEle = strUUID + std::string(",") + strTotal + std::string(",") + strIndex + std::string(",") + strSLLE.substr(0, MAX_SLLE_LENGTH);
                strSLLE.erase(strSLLE.begin(), strSLLE.begin() + MAX_SLLE_LENGTH);
            }

            Poco::Mutex::ScopedLock lock(m_mutexSLLEData);
            m_vectSLLEData.push_back(strEle);
            g_NetLog.Debug("gj slle push %s\n", strEle.c_str());
        } while (strSLLE.size() > 0);
    }
    else
    {
        std::string strEle = strUUID + std::string(",1,0,") + strSLLE;
        m_vectSLLEData.push_back(strEle);
    }
}

std::string SLLE::read()
{
    Poco::Mutex::ScopedLock lock(m_mutexSPHYData);
    if (m_vectSPHYData.empty())
    {
        return "";
    }
    for (size_t i = 0; i < m_vectSPHYData.size(); ++i)
    {
        Debug0(m_vectSPHYData[i]);
        if (m_vectSPHYData[i].m_iCurIndex + 1 == m_vectSPHYData[i].m_iTotal)
        {
            if (m_vectSPHYData[i].m_strData.empty())
            {
                continue;
            }
            string strData = m_vectSPHYData[i].m_strData;
            string strNULL;
            g_NetLog.Debug("gj swap uuid %s data %s\n", m_vectSPHYData[i].m_strUUID.c_str(), strData.c_str());
            m_vectSPHYData[i].m_strData.swap(strNULL);
            return strData;
        }
        else if (!m_vectSPHYData[i].m_strData.empty())
        {
            Poco::Clock clk;
            if ((clk.microseconds() - m_vectSPHYData[i].m_clkInsert) / (1000 * 1000) > m_vectSPHYData[i].m_iTotal * 5)
            {
                string strNULL;
                g_NetLog.Debug("gj swap nouse\n");
                m_vectSPHYData[i].m_strData.swap(strNULL);
            }
        }
        else
        {
            ;
        }
    }
    return "";
}

SLLE::SLLE()
{
    m_bStop = true;
}

SLLE::~SLLE()
{

}

void SLLE::run()
{
    g_NetLog.Debug("gj lle start\n");
    while (!m_bStop || 1)
    {
        Routine();
        Poco::Thread::sleep(10);
    }
}

void SLLE::Routine()
{
    try
    {
        std::string strWrite;
        do 
        {
            if (1)
            {
                strWrite.clear();
                Poco::Mutex::ScopedLock lock(m_mutexSLLEData);
                if (!m_vectSLLEData.empty())
                {
                    strWrite = m_vectSLLEData[0];
                    m_vectSLLEData.erase(m_vectSLLEData.begin());
                }
            }
            if (!strWrite.empty())
            {
                SPHY::GetInstance()->Write(strWrite);
            }
            ReadSPHYData();
        } while (!strWrite.empty());
    }
    catch (...)
    {
        g_NetLog.Error("catched\n");
    }
}

void SLLE::ReadSPHYData()
{
    std::string strSPHYData = SPHY::GetInstance()->Read();
    if (strSPHYData.empty())
    {
        return;
    }
    Poco::StringTokenizer strToken(strSPHYData, ",", 3);
    if (strToken.count() < 4)
    {
        return;
    }

    SPHYData sphyData;
    sphyData.m_strUUID = strToken[0];
    sphyData.m_iTotal = String2Int(strToken[1]);
    sphyData.m_iCurIndex = String2Int(strToken[2]);
    Poco::Clock clk;
    sphyData.m_clkInsert = clk.microseconds();
    int iIndex0 = strSPHYData.find(string(","));
    int iIndex1 = strSPHYData.find(string(","), iIndex0 + 1);
    int iIndex2 = strSPHYData.find(string(","), iIndex1 + 1);
    sphyData.m_strData = strSPHYData.substr(iIndex2 + 1);
    int iIndex = CheckSPHYData(sphyData);
    if (iIndex >= 0)
    {
        g_NetLog.Debug("gj slle read0 from phy index %d uuid %s data %s\n", iIndex, sphyData.m_strUUID.c_str(), strSPHYData.c_str());
        m_vectSPHYData[iIndex].m_strData.append(sphyData.m_strData);
        m_vectSPHYData[iIndex].m_iCurIndex = sphyData.m_iCurIndex;
        m_vectSPHYData[iIndex].m_clkInsert = sphyData.m_clkInsert;
    }
    else if (iIndex != -2)
    {
        g_NetLog.Debug("gj slle read1 from phy index %d uuid %s data %s\n", iIndex, sphyData.m_strUUID.c_str(), strSPHYData.c_str());
        Poco::Mutex::ScopedLock lock(m_mutexSPHYData);
        m_vectSPHYData.push_back(sphyData);
    }
    if (m_vectSPHYData.size() > 10)
    {
        m_vectSPHYData.erase(m_vectSPHYData.begin());
    }
}

int SLLE::CheckSPHYData(SPHYData sphyData)
{
    Poco::Mutex::ScopedLock lock(m_mutexSPHYData);
    for (size_t i = 0; i < m_vectSPHYData.size(); ++i)
    {
        if (m_vectSPHYData[i].m_strUUID == sphyData.m_strUUID)
        {
            if (m_vectSPHYData[i].m_iCurIndex + 1 == sphyData.m_iCurIndex && sphyData.m_iCurIndex < m_vectSPHYData[i].m_iTotal)
            {
                return i;
            }
            else
            {
                return -2;
            }
        }
    }
    return -1;
}

void SLLE::Debug0(SPHYData sphyData)
{
    if (sphyData.m_strData.empty())
    {
        return;
    }
    if (m_mapDebugUUID2Index.find(sphyData.m_strUUID) != m_mapDebugUUID2Index.end())
    {
        if (m_mapDebugUUID2Index[sphyData.m_strUUID] < sphyData.m_iCurIndex)
        {
            g_NetLog.Debug("SLLE::read 0 uuid %s cur [%d] total [%d]\n", sphyData.m_strUUID.c_str(), sphyData.m_iCurIndex, sphyData.m_iTotal);
            g_NetLog.Debug("gj SLLE::read 0 uuid %s cur [%d] total [%d]\n", sphyData.m_strUUID.c_str(), sphyData.m_iCurIndex, sphyData.m_iTotal);
            m_mapDebugUUID2Index[sphyData.m_strUUID] = sphyData.m_iCurIndex;
        }
    }
    else
    {
        g_NetLog.Debug("SLLE::read 1 uuid %s cur [%d] total [%d]\n", sphyData.m_strUUID.c_str(), sphyData.m_iCurIndex, sphyData.m_iTotal);
        g_NetLog.Debug("gj SLLE::read 1 uuid %s cur [%d] total [%d]\n", sphyData.m_strUUID.c_str(), sphyData.m_iCurIndex, sphyData.m_iTotal);
        m_mapDebugUUID2Index[sphyData.m_strUUID] = sphyData.m_iCurIndex;
    }
}

std::string SLLE::Int2String(int i)
{
    char buf[10] = { 0 };
    sprintf(buf, "%d", i);
    return buf;
}

int SLLE::String2Int(std::string s)
{
    int i;
    sscanf(s.c_str(), "%d", &i);
    return i;
}
